/*******************************************************************************
** 文件名称：serialport.c
** 文件作用：串口处理-中间层
** 编写作者：TomFree <付瑞彪>
** 编写时间：2019-12-21
** 文件备注：
**
** 更新记录：
**           2019-12-21 -> 创建文件                                 <Tom Free>
**
**           1 Tab == 4 Spaces     UTF-8     ANSI C Language
*******************************************************************************/

#include "serialport.h"
#include "uart0.h"
#include "stdio.h"
#include "stdarg.h"
#include "delay.h"

/* 串口参数结构 */
static struct _SERIAL_PORT
{
    GM_U8             InitFlag; /* 初始化标志 */
    QUEUE             RxQueue;  /* 接收队列 */
    QUEUE             TxQueue;  /* 发送队列 */
    SERIAL_PORT_DRIVE Drive;    /* 驱动 */
} SerialPort[SERIAL_PORT_NUM_MAX];

/*******************************************************************************
** 函数名称：SerialPort_DriveInit
** 函数作用：驱动初始化
** 输入参数：sp_num - 串口号，从0开始，最大不可超过[SERIAL_PORT_NUM_MAX]
**          drv    - 驱动指针
** 输出参数：是否成功
** 使用范例：SerialPort_DriveInit(0, drv);
** 函数备注：使用串口之前一定要初始化此驱动
*******************************************************************************/
GM_BOOL SerialPort_DriveInit(GM_U8 sp_num, SERIAL_PORT_DRIVE* drv)
{
    if ((drv == GM_NULL) ||
        (drv->QueryRxComplete == GM_NULL) ||
        (drv->QueryTxIdle == GM_NULL) ||
        (drv->RxByte == GM_NULL) ||
        (drv->TxByte == GM_NULL))
    {
        SerialPort[sp_num].InitFlag = 0x00;
        return GM_FALSE;
    }

    SerialPort[sp_num].Drive.QueryRxComplete = drv->QueryRxComplete;
    SerialPort[sp_num].Drive.QueryTxIdle = drv->QueryTxIdle;
    SerialPort[sp_num].Drive.RxByte = drv->RxByte;
    SerialPort[sp_num].Drive.TxByte = drv->TxByte;

    SerialPort[sp_num].InitFlag |= 0x01;
    return GM_TRUE;
}

/*******************************************************************************
** 函数名称：SerialPort_QueueInit
** 函数作用：初始化串口的队列
** 输入参数：sp_num      - 串口号，从0开始，最大不可超过[SERIAL_PORT_NUM_MAX]
**           rx_buf      - 接收队列缓冲区起始地址
**           rx_buf_size - 接收队列缓冲区大小
**           tx_buf      - 发送队列缓冲区起始地址
**           tx_buf_size - 发送队列缓冲区大小
** 输出参数：是否成功
** 使用范例：SerialPort_QueueInit(0, &buf1, 10, &buf2, 30);
** 函数备注：使用串口之前一定要初始化队列
*******************************************************************************/
GM_BOOL SerialPort_QueueInit(GM_U8 sp_num,          /* 串口号 */
                             GM_U8* rx_buf,         /* 接收buf地址 */
                             GM_U16 rx_buf_size,    /* 接收buf长度 */
                             GM_U8* tx_buf,         /* 发送buf地址 */
                             GM_U16 tx_buf_size)    /* 发送buf长度 */
{
    if ((sp_num >= SERIAL_PORT_NUM_MAX) ||
        (rx_buf == GM_NULL) ||
        (rx_buf_size == 0)  ||
        (rx_buf == GM_NULL) ||
        (tx_buf_size == 0))
    {
        SerialPort[sp_num].InitFlag = 0x00;
        /* 非法数据 */
        return GM_FALSE;
    }

    /* 初始化队列 */
    Queue_Init(&SerialPort[sp_num].RxQueue, rx_buf, rx_buf_size);
    Queue_Init(&SerialPort[sp_num].TxQueue, tx_buf, tx_buf_size);

    SerialPort[sp_num].InitFlag |= 0x02;
    return GM_TRUE;
}

/*******************************************************************************
** 函数名称：SerialPort_ReceiveByteHandler
** 函数作用：串口接收一个字符处理
** 输入参数：sp_num  - 串口号，从0开始，最大不可超过[SERIAL_PORT_NUM_MAX]
** 输出参数：是否保存成功
** 使用范例：GM_BOOL res = SerialPort_ReceiveByteHandler(0);
** 函数备注：此函数一般放在接收中断中或查询接收标志处理任务中
*******************************************************************************/
GM_BOOL SerialPort_ReceiveByteHandler(GM_U8 sp_num)
{
    GM_U8 temp;

    if ((SerialPort[sp_num].InitFlag & 0x03) != 0X03)
    {
        /* 未初始化OK */
        return GM_FALSE;
    }

    if (SerialPort[sp_num].Drive.QueryRxComplete() == GM_TRUE)
    {
        /* 收到数据 */
        temp = SerialPort->Drive.RxByte();
        return Queue_Write(&SerialPort[sp_num].RxQueue, temp);
    }
    else
    {
        /* 未收到数据 */
        return GM_FALSE;
    }
}

/*******************************************************************************
** 函数名称：SerialPort_SendByteHandler
** 函数作用：串口发送一个字符处理
** 输入参数：sp_num - 串口号，从0开始，最大不可超过[SERIAL_PORT_NUM_MAX]
** 输出参数：是否发送OK，GM_TRUE - 发送OK，GM_FALSE - 数据发完，空闲了
** 使用范例：SerialPort_SendByteHandler
** 函数备注：此函数一般放在发送中断中或查询发送标志处理任务中
*******************************************************************************/
GM_BOOL SerialPort_SendByteHandler(GM_U8 sp_num)
{
    GM_U8 tx_data;

    if ((SerialPort[sp_num].InitFlag & 0x03) != 0X03)
    {
        /* 未初始化OK */
        return GM_FALSE;
    }

    if (SerialPort->Drive.QueryTxIdle() != GM_TRUE)
    {
        /* 数据发送中 */
        return GM_FALSE;
    }

    if (Queue_Read(&SerialPort[sp_num].TxQueue, &tx_data) == GM_TRUE)
    {
        /* 有数据就发送 */
        SerialPort->Drive.TxByte(tx_data);
        return GM_TRUE;
    }
    else
    {
        /* 无数据 */
        return GM_FALSE;
    }
}

/*******************************************************************************
** 函数名称：SerialPort_WriteByte
** 函数作用：无阻塞写数据
** 输入参数：sp_num  - 串口号，从0开始，最大不可超过[SERIAL_PORT_NUM_MAX]
**          tx_data - 待发送数据
** 输出参数：无
** 使用范例：SerialPort_WriteByte();
** 函数备注：
*******************************************************************************/
void SerialPort_WriteByte(GM_U8 sp_num, GM_U8 tx_data)
{
    Queue_Write(&SerialPort[sp_num].TxQueue, tx_data);
}

/*******************************************************************************
** 函数名称：SerialPort_ReadByte
** 函数作用：无阻塞读数据
** 输入参数：sp_num  - 串口号，从0开始，最大不可超过[SERIAL_PORT_NUM_MAX]
**           rx_data - 读取的数据
** 输出参数：是否接收到数据
** 使用范例：SerialPort_ReadByte();
** 函数备注：
*******************************************************************************/
GM_BOOL SerialPort_ReadByte(GM_U8 sp_num, GM_U8* rx_data)
{
    return Queue_Read(&SerialPort[sp_num].RxQueue, rx_data);
}

/*******************************************************************************
** 函数名称：SerialPort_PutString
** 函数作用：打印字符串
** 输入参数：sp_num  - 串口号，从0开始，最大不可超过[SERIAL_PORT_NUM_MAX]
**           str     - 字符串
** 输出参数：无
** 使用范例：SerialPort_PutString(0, "hello\r\n");
** 函数备注：
*******************************************************************************/
void SerialPort_PutString(GM_U8 sp_num, const char* str)
{
    while (*str)
    {
        SerialPort_WriteByte(sp_num, *str);
        str++;
    }
}

/*******************************************************************************
** 函数名称：SerialPort_Printf
** 函数作用：printf函数
** 输入参数：sp_num  - 串口号，从0开始，最大不可超过[SERIAL_PORT_NUM_MAX]
**           fmt - 格式化字符串
** 输出参数：无
** 使用范例：SerialPort_Printf(0, "%d\r\n", 287);
** 函数备注：
*******************************************************************************/
void SerialPort_Printf(GM_U8 sp_num, const char * fmt, ...)
{
    char vs_str[64];
    va_list ap;
    va_start(ap, fmt);
    vsprintf(vs_str, fmt, ap);
    SerialPort_PutString(sp_num, vs_str);
    va_end(ap);
}
